/*
 * ---------------------------------------------------------------------
 * Copyright (c) 2014, 2015 All Right Reserved
 * This software is developed for study and improve coding skill ...
 *
 * Project:  Excellent Coding< EC >
 *
 * ecThread.cpp
 * This file for EC thread interface & encapsulation implementation.
 *
 * Eamil:   epengao@126.com
 * Author:  Peter Gao
 * Version: Intial first version.
 * --------------------------------------------------------------------
 */

#include "ecOSUtil.h"
#include "ecThread.h"
#include "ecStringOP.h"
#include "ecAutoLock.h"
#include "ecMsgProcCQ.h"

namespace ec {

ecThread::ecThread(
                   EC_PCHAR pThreadName, /*=EC_NULL*/
                   ecThreadType nThreadType, /*=ecThreadType_Nomal*/
                   EC_U32 nMsgListSize /*=MAX_THREAD_MSG_QUEUE*/
                  )
:m_pName(EC_NULL)
,m_nType(nThreadType)
,m_nStatus(ecThreadStatus_Init)
,m_pMsgList(EC_NULL)
{
    if (NULL != pThreadName)
    {
        m_pName = new char[ecStrLen(pThreadName) + 1];
        strcpy(m_pName, pThreadName);
    }

    switch(nThreadType)
    {
        case ecThreadType_MsgCQ:
        {
            m_pMsgList = new ecMsgProcCQ(nMsgListSize);
        }
        break;
            
        default:
        {
            m_pMsgList = new ecMsgProcCQ(nMsgListSize);
        }
        break;
    }

#ifdef _WIN32
    m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncEntry, this, 0, &m_nThreadID);
#else
    pthread_create(&m_ThreadHandle, NULL, ThreadFuncEntry, this);
#endif
}

ecThread::~ecThread()
{
    if(ecThreadStatus_Stop != m_nStatus)
        Stop();

#ifdef _WIN32
    CloseHandle(m_hThread);
#else
    pthread_join(m_ThreadHandle, NULL);
#endif

    if(m_pName)
        delete m_pName;
    if(m_pMsgList)
        delete m_pMsgList;
}

void ecThread::Run()
{
    m_nStatus = ecThreadStatus_Run;
}

void ecThread::Pause()
{
    m_nStatus = ecThreadStatus_Pause;
}

void ecThread::Stop()
{
    if(ecThreadStatus_Stop == m_nStatus)
        return;

    m_nStatus = ecThreadStatus_Stop;
    if(m_pMsgList)
    {
        ecAutoLock Lock(&m_mtxMsgList);
        m_pMsgList->ClearMsg();
    }
}

EC_U32 ecThread::PostMsg(ecMessage* pMsg)
{
    if(ecThreadStatus_Run != m_nStatus)
        return EC_Err_OperatorFaild;

    if(m_pMsgList)
    {
        {
            ecAutoLock Lock(&m_mtxMsgList);
            m_pMsgList->PostMsg(pMsg);
        }
        m_semMsgSignal.SemAddSIGNAL();
    }
    return EC_Err_None;
}

void ecThread::OnMsg()
{
    ecMessage* pMsg = EC_NULL;
    if(m_pMsgList)
    {
        ecAutoLock Lock(&m_mtxMsgList);
        pMsg = m_pMsgList->GetMsg();
    }
    if(pMsg)
    {
        pMsg->Fire();
        delete pMsg;
    }
}

void* ecThread::ThreadFuncEntry(void* pArg)
{
    if(EC_NULL == pArg)
        return EC_NULL;

    ecThread* pThreadHandle = (ecThread*)pArg;
    while(EC_TRUE)
    {
        switch (pThreadHandle->m_nStatus)
        {
            case ecThreadStatus_Init:
            {
                ecSleep(10);
            }
            break;

            case ecThreadStatus_Run:
            {
                pThreadHandle->m_semMsgSignal.SemRemoveSIGNAL();
                pThreadHandle->OnMsg();
            }
            break;

            case ecThreadStatus_Pause:
            {
                ecSleep(50);
            }
            break;

            case ecThreadStatus_Stop:
            {
                return NULL;
            }
            break;

            default: return NULL;
        }
    }
}
} /* namespace ec */